trait Base extends { g |
	trait Any extends { this0 | };
    type Boolean = $fs$.Boolean;
    type String = $fs$.String;
	type Unit = $fs$.Unit;
	type Bottom = $fs$.Bottom;
	
	trait Console extends {
		def println(s :g.String): g.Unit = $fs$.println(s)
		def print(s :g.String): g.Unit = $fs$.print(s)
	};	
	val console :g.Console = new g.Console;
	def error(s :g.String): g.Bottom =  $fs$.error(s)
	
	trait Function extends  { this0 | 
      type Dom 
      type Range 
      def apply(x : this0.Dom): this0.Range 
	}
};

trait ListComponent extends Base { g |	
	trait List extends g.Any { this0 | 
		type Elem 
		type ListOfElem = g.List  { this1 | type Elem = this0.Elem } 
		def isEmpty(): g.Boolean 
		def head(): this0.Elem 
		def tail(): this0.ListOfElem 
	} 

	trait Nil extends g.List { this0 | 
		def isEmpty(): g.Boolean = true 
		def head(): this0.Elem = g.error("Nil.head") 
		def tail(): this0.ListOfElem = g.error("Nil.tail") 
	} 
	
	trait Cons extends g.List { this0 | 
		val hd : this0.Elem 
		val tl : this0.ListOfElem 
		def isEmpty(): g.Boolean = false 
		def head(): this0.Elem = this0.hd 
		def tail(): this0.ListOfElem = this0.tl 
	} 
};

trait MapComponent extends ListComponent { g |
  trait Mapper extends { this0 | 
    type A 
    type B 
  
    def map(f: g.Function{type Dom = this0.A; type Range = this0.B}, xs: g.List{type Elem = this0.A}): g.List{type Elem = this0.B} 
      = if (xs.isEmpty()) ((new g.Nil { type Elem = this0.B }) : g.List{type Elem = this0.B})
        else ((new g.Cons { this1 | 
                        type Elem = this0.B
                        val hd: this1.Elem = f.apply(xs.head()) 
                        val tl: this1.ListOfElem = this0.map(f, xs.tail())}): g.List{type Elem = this0.B} )
  };
};

val g = new ListComponent;

val bla  = new g.Cons { type Elem = g.Boolean; val hd : this.Elem = true; 
                        val tl : this.ListOfElem = new g.Nil { type Elem = g.Boolean }}; // try  type Elem = g.String ;-)
unit // type of program must not contain any variables local to the program

// TODO: scanner freaks out if file does not end in whitespace
